#version 450

//enable #include
#extension GL_GOOGLE_include_directive : enable
#extension GL_EXT_nonuniform_qualifier : require

#include "PBRCommon.h"


layout (input_attachment_index = 0, binding = 0) uniform subpassInput samplerAlbedo;
layout (input_attachment_index = 1, binding = 1) uniform subpassInput samplerposition;
layout (input_attachment_index = 2, binding = 2) uniform subpassInput samplerNormal;
layout (input_attachment_index = 3, binding = 3) uniform subpassInput samplerMisc;


layout (location = 0) out vec4 outColor;

#define CascadeNum 4


layout (set=1, binding = 0) uniform sampler2D DirectionalLightShadowMap[];

layout (set=1 ,binding=1  ) uniform SDirectionalLightBuffer
{
    mat4 LightVP[CascadeNum];

    // used to get the correct shadow map, the last one is 1.0
    // array stride will be expanded to 16 bytes rather than 4 bytes
    float MaxDepths[CascadeNum]; 
    vec3 LightDirection; //normalized
    float Padding;
    vec3 LightColorWithIntensity;
    float Padding2;
    vec3 ViewPos; //camera position
    float Padding3;
    float ShadowBias; 
} UBO;

void main() 
{
	// Read G-Buffer values from previous sub pass
	vec3 normal = subpassLoad(samplerNormal).rgb;

    if(normal==vec3(0.0))
    {
        //for unlit meshes
        discard;
    }

	vec3 fragPos = subpassLoad(samplerposition).rgb;
	vec3 albedo = subpassLoad(samplerAlbedo).rgb;
	
    float ao=subpassLoad(samplerAlbedo).a;
	float metallic=subpassLoad(samplerposition).a;
	float roughness=subpassLoad(samplerNormal).a;

    vec3 V=normalize(UBO.ViewPos.xyz-fragPos);
	vec3 N=normal;
    //base reflectance
    vec3 F0=vec3(0.04);
    F0=mix(F0,albedo,metallic);

    vec3 Sum=vec3(0.0);

    //light by directional light
    {
        float CameraDepth=subpassLoad(samplerMisc).r;
        
        int CascadeIndex=0;
        for(int i=0;i<CascadeNum;i++)
        {
            if(CameraDepth > UBO.MaxDepths[i])
            {
                CascadeIndex=i+1;
            }
            else
            {
                break;
            }
        }


        vec4 UnnormalizedLightSpacePosition=UBO.LightVP[CascadeIndex] * vec4(fragPos,1);
        vec3 LightSpacePosition=UnnormalizedLightSpacePosition.xyz / UnnormalizedLightSpacePosition.w;
        // vec2 ShadowMapUV= LightSpacePosition.xy *0.5 +0.5;
        
        //if(ShadowMapUV.x >=0 && ShadowMapUV.y >=0  && ShadowMapUV.x <=1 && ShadowMapUV.y <=1 )
        // {
        //     float ShadowMapDepth= texture(DirectionalLightShadowMap[CascadeIndex],ShadowMapUV).r +UBO.ShadowBias;
        //     if(LightSpacePosition.z >  ShadowMapDepth)
        //     {
        //         //is in shadow
        //         discard;
        //     }
        // }

        //使用PCF让阴影更加柔和
        float Shadow=0.0;
        vec2 texelSize=1.0/ textureSize(DirectionalLightShadowMap[CascadeIndex],0);
        vec2 ShadowMapUVInMiddle= LightSpacePosition.xy *0.5 +0.5;
        {
            //Left 
            vec2 Offset=vec2(-1,0);
            vec2 ShadowMapUV=ShadowMapUVInMiddle + Offset*texelSize;
            float ShadowMapDepth= texture(DirectionalLightShadowMap[CascadeIndex],ShadowMapUV).r +UBO.ShadowBias;
            Shadow+=LightSpacePosition.z >  ShadowMapDepth  
                ?0.0 //在阴影中
                :1.0f;  //不在阴影中
        }

        {
            //Right
            vec2 Offset=vec2(1,0);
            vec2 ShadowMapUV= ShadowMapUVInMiddle + Offset*texelSize;
            float ShadowMapDepth= texture(DirectionalLightShadowMap[CascadeIndex],ShadowMapUV).r +UBO.ShadowBias;
            Shadow+=LightSpacePosition.z >  ShadowMapDepth
                ?0.0 //在阴影中
                :1.0f;  //不在阴影中  
        }

        {
            //Top
            vec2 Offset=vec2(0,1);
            vec2 ShadowMapUV= ShadowMapUVInMiddle + Offset*texelSize;
            float ShadowMapDepth= texture(DirectionalLightShadowMap[CascadeIndex],ShadowMapUV).r +UBO.ShadowBias;
            Shadow+=LightSpacePosition.z >  ShadowMapDepth
                ?0.0 //在阴影中
                :1.0f;  //不在阴影中
        }

        {
            //Bottom
            vec2 Offset=vec2(0,-1);
            vec2 ShadowMapUV= ShadowMapUVInMiddle + Offset*texelSize;
            float ShadowMapDepth= texture(DirectionalLightShadowMap[CascadeIndex],ShadowMapUV).r +UBO.ShadowBias;
            Shadow+=LightSpacePosition.z >  ShadowMapDepth
                ?0.0 //在阴影中
                :1.0f;  //不在阴影中
        }

        {
            //Middle
            float ShadowMapDepth= texture(DirectionalLightShadowMap[CascadeIndex],ShadowMapUVInMiddle).r +UBO.ShadowBias;
            Shadow+=LightSpacePosition.z >  ShadowMapDepth
                ?0.0 //在阴影中
                :2.0f;  //不在阴影中,中间的权重更大
        }

        {
            //LeftTop
            vec2 Offset=vec2(-0.707,0.707);
            vec2 ShadowMapUV= ShadowMapUVInMiddle + Offset*texelSize;
            float ShadowMapDepth= texture(DirectionalLightShadowMap[CascadeIndex],ShadowMapUV).r +UBO.ShadowBias;
            Shadow+=LightSpacePosition.z >  ShadowMapDepth
                ?0.0 //在阴影中
                :1.0f;  //不在阴影中
        }

        {
            //RightTop
            vec2 Offset=vec2(0.707,0.707);
            vec2 ShadowMapUV= ShadowMapUVInMiddle + Offset*texelSize;
            float ShadowMapDepth= texture(DirectionalLightShadowMap[CascadeIndex],ShadowMapUV).r +UBO.ShadowBias;
            Shadow+=LightSpacePosition.z >  ShadowMapDepth
                ?0.0 //在阴影中
                :1.0f;  //不在阴影中
        }

        {
            //LeftBottom
            vec2 Offset=vec2(-0.707,-0.707);
            vec2 ShadowMapUV= ShadowMapUVInMiddle + Offset*texelSize;
            float ShadowMapDepth= texture(DirectionalLightShadowMap[CascadeIndex],ShadowMapUV).r +UBO.ShadowBias;
            Shadow+=LightSpacePosition.z >  ShadowMapDepth
                ?0.0 //在阴影中
                :1.0f;  //不在阴影中
        }

        {
            //RightBottom
            vec2 Offset=vec2(0.707,-0.707);
            vec2 ShadowMapUV= ShadowMapUVInMiddle + Offset*texelSize;
            float ShadowMapDepth= texture(DirectionalLightShadowMap[CascadeIndex],ShadowMapUV).r +UBO.ShadowBias;
            Shadow+=LightSpacePosition.z >  ShadowMapDepth
                ?0.0 //在阴影中
                :1.0f;  //不在阴影中
        }

        float WeightSum=10;
        Shadow/=WeightSum;

        if(Shadow < 0.1)
        {
            discard;
        }

        vec3 LightDir=-UBO.LightDirection;
        vec3 Half=normalize(V+LightDir);

        //calculate radiance
        vec3  radiance=UBO.LightColorWithIntensity;

        //cook-torrance BRDF
        float NDF=DistributionGGX(N,Half,roughness);
        float G=GeometrySmith(N, V, LightDir, roughness);   
        vec3  F=fresnelSchlick(max(dot(Half, V), 0.0), F0);

        vec3 numerator=NDF*G*F;
        float denominator=4.0 * max(dot(N, V), 0.0) * max(dot(N, LightDir), 0.0) + 0.0001; // + 0.0001 to prevent divide by zero
        vec3 specular= numerator/denominator;

        vec3 Ks=F;
        vec3 Kd=vec3(1.0)-Ks; 
        Kd*=1.0-metallic;

        float NdotL=max(dot(N,LightDir),0.0);
        
        Sum+=(Kd*albedo/PI +specular)* radiance * NdotL * Shadow;
    }

    // HDR tonemapping
    vec3 Color = Sum / (Sum + vec3(1.0));

    outColor=vec4(Color,1.0);

}